package fiuba.algo3.control;

import java.util.ArrayList;
import fiuba.algo3.Ciudad;
import fiuba.algo3.Edificio;
import fiuba.algo3.Juego;
import fiuba.algo3.Pista;
import fiuba.algo3.vista.VistaConsola;
import fiuba.algo3.vista.VistaInstructivo;
import fiuba.algo3.vista.VistaOrdenDeArresto;
import fiuba.algo3.vista.VistaPista;

public class Controlador {
	Juego modelo;
	VistaConsola vista;
	boolean ladronAtrapado;
	boolean ladronEscapo;
	ArrayList<Edificio> edificiosSiendoVisitados = null;

	public Controlador(Juego modelo) {
		this.modelo = modelo;
		this.ladronAtrapado = false;
		this.ladronEscapo = false;
	}
	
	public Juego getModelo(){
		return this.modelo;
	}
	
	public VistaConsola getVista(){
		return this.vista;
	}

	public void setVista(VistaConsola vista) {
		this.vista = vista;
	}
	
	public boolean ladronAtrapado(){
		return this.ladronAtrapado;
	}

	public boolean ladronEscapo(){
		return this.ladronEscapo;
	}
	
	public void leerEntradaAgente(String nombre) throws Exception {
		if ( modelo.existePartida(nombre) ){
			this.modelo = Juego.cargarPartida(nombre + ".xml");
			this.vista.setModelo(this.modelo);
			this.vista.mensajeBienvenida(false);
			this.vista.estadoDelJuego();
		}
		else{
			this.modelo.generarCaso();
			this.modelo.setNombrePolicia(nombre);
			this.vista.mensajeBienvenida(true);
			this.vista.pistaSexoLadron();
			vista.estadoDelJuego();
		}
	}
	
	public boolean escucharMenuDeOpciones(int opc) throws Exception {
		switch (opc){
		// desea salir, le pregunto si quiere salir sin guardar.
		case 0:
			int opcion_salir = this.vista.menuDeseaSalir();
			boolean salir = this.escucharDeseaSalir(opcion_salir);
			if (salir){
				return true;
			}
			else{
				return false;
			}
		// quiere viajar, veo si es la ultima ciudad o no.
		case 1:
			if ( !modelo.getMapa().esUltimaCiudad( modelo.getPolicia().getCiudadActual() ) )
			{
				ArrayList<Ciudad> ciudades = modelo.ofrecerOpcionesCiudadAVisitar();
				edificiosSiendoVisitados = null;
				int opcion_ciudad = vista.menuCiudadesParaViajar(ciudades);
				this.escucharMenuCiudades(ciudades, opcion_ciudad); break;
			}
			else{
				// es ultima ciudad, no muestro mas ciudades
				// mantengo el menu anterior
				vista.mensajeUltimaCiudad();
				break;
			}
		// quiere visitar edificio, veo que no haya un trio de edificios ya creado.
		case 2:
			ArrayList<Edificio> edificios = edificiosSiendoVisitados; 
			if (edificiosSiendoVisitados == null){
				edificios = modelo.ofrecerOpcionesEdificioAVisitar();
				edificiosSiendoVisitados = edificios;
			}
			int opcion_edificio = vista.menuEdificiosParaVisitar(edificios);
			this.escucharMenuEdificios(edificios, opcion_edificio);
			break;
		// quiere ver orden de arresto
		case 3:
			int opcion_orden = vista.menuOrdenDeArresto();
			this.escucharMenuOrden(opcion_orden);
			break;
		// quiere guardar partido, verifico que se pueda.
		case 4:
			try{
				modelo.guardarPartida();
				vista.mensajeGuardarExito();
			}
			catch (Exception e){
				vista.mensajeGuardarError();
			}
			break;
		case 5:
			// mostrar instrucciones
			VistaInstructivo instrucciones = new VistaInstructivo();
			instrucciones.mostrarInstructivo();
			vista.estadoDelJuego();
		}
		return false;
	}
	
	public boolean finDelTiempo(){
		if (modelo.getPolicia().tiempoCumplido())
			return true;
		return false;
	}

	public void escucharMenuCiudades(ArrayList<Ciudad> ciudades, int opc) throws Exception {
		Ciudad ciudad = ciudades.get(opc-1);
		VistaPista pistaLadron = new VistaPista( modelo.policiaViaja(ciudad) );
		if (pistaLadron != null){
			pistaLadron.printPistaLadron();
		}
		if (this.finDelTiempo())
			return;
		vista.estadoDelJuego();
	}

	public void escucharMenuEdificios(ArrayList<Edificio> edificios, int opc) throws Exception {
		Edificio edificio = edificios.get(opc-1);
		modelo.setEdificioAVisitar(edificio);
		Pista pista = modelo.policiaObtienePista();
		if (this.finDelTiempo())
			return;
		if (pista != null){
			VistaPista vistaPista = new VistaPista(pista);
			vistaPista.print();
			vista.estadoDelJuego();
		}
		else{
			// verifico si encontre al ladron
			if (modelo.casoGanado())
				this.ladronAtrapado = true;
			else
				this.ladronEscapo = true;
		}
	}

	public void escucharMenuOrden(int opc) throws Exception {
		switch (opc){
		case 0:
			break;
		case 1:
			int opcion_sexo = vista.modificarSexo();
			this.escucharModificarSexo(opcion_sexo); 
			int opcion_orden = vista.menuOrdenDeArresto();
			this.escucharMenuOrden(opcion_orden); 
			break;
		case 2:
			int opcion_hobby = vista.modificarHobby();
			this.escucharModificarHobby(opcion_hobby); 
			 opcion_orden = vista.menuOrdenDeArresto();
			this.escucharMenuOrden(opcion_orden); 
			break;
		case 3:
			int opcion_cabello = vista.modificarCabello();
			this.escucharModificarCabello(opcion_cabello); 
			 opcion_orden = vista.menuOrdenDeArresto();
			this.escucharMenuOrden(opcion_orden); 
			break;
		case 4:
			int opcion_senia = vista.modificarSenia();
			this.escucharModificarSenia(opcion_senia); 
			 opcion_orden = vista.menuOrdenDeArresto();
			this.escucharMenuOrden(opcion_orden); 
			break;
		case 5:
			int opcion_auto = vista.modificarAuto();
			this.escucharModificarAuto(opcion_auto); 
			 opcion_orden = vista.menuOrdenDeArresto();
			this.escucharMenuOrden(opcion_orden); 
			break;
		case 6:
			boolean ordenAprobada = modelo.policiaEmiteOrdenDeArresto();
			VistaOrdenDeArresto vistaOrden = new VistaOrdenDeArresto(modelo.getPolicia().getOrdenDeArresto());
			vista.mostrarValidacionOrdenDeArresto(vistaOrden, ordenAprobada);
			if (this.finDelTiempo())
				return;
			int opcion = vista.menuOrdenDeArresto();
			this.escucharMenuOrden(opcion);
			break;
		}
	}

	public void escucharModificarSexo(int opc) throws Exception {
		switch (opc){
		case 0:
			modelo.getPolicia().ingresarSexoSospechoso(""); break;
		case 1:
			modelo.getPolicia().ingresarSexoSospechoso("masculino"); break;
		case 2:
			modelo.getPolicia().ingresarSexoSospechoso("femenino"); break;
		}
	}

	public void escucharModificarHobby(int opc) throws Exception {
		switch (opc){
		case 0:
			modelo.getPolicia().ingresarHobbySospechoso("");break;
		case 1:
			modelo.getPolicia().ingresarHobbySospechoso("alpinismo");break;
		case 2:
			modelo.getPolicia().ingresarHobbySospechoso("croquet");break;
		case 3:
			modelo.getPolicia().ingresarHobbySospechoso("tenis");break;
		}
	}

	public void escucharModificarCabello(int opc) throws Exception {
		switch (opc){
		case 0:
			modelo.getPolicia().ingresarCabelloSospechoso("");break;
		case 1:
			modelo.getPolicia().ingresarCabelloSospechoso("negro");break;
		case 2:
			modelo.getPolicia().ingresarCabelloSospechoso("rojo");break;
		case 3:
			modelo.getPolicia().ingresarCabelloSospechoso("castanio");break;
		case 4:
			modelo.getPolicia().ingresarCabelloSospechoso("rubio");break;
		}
	}

	public void escucharModificarSenia(int opc) throws Exception {
		switch (opc){
		case 0:
			modelo.getPolicia().ingresarSeniaSospechoso("");break;
		case 1:
			modelo.getPolicia().ingresarSeniaSospechoso("anillo");break;
		case 2:
			modelo.getPolicia().ingresarSeniaSospechoso("tatuaje");break;
		case 3:
			modelo.getPolicia().ingresarSeniaSospechoso("joyas");break;
		}
	}

	public void escucharModificarAuto(int opc) throws Exception {
		switch (opc){
		case 0:
			modelo.getPolicia().ingresarAutoSospechoso("");break;
		case 1:
			modelo.getPolicia().ingresarAutoSospechoso("moto");break;
		case 2:
			modelo.getPolicia().ingresarAutoSospechoso("descapotable");break;
		case 3:
			modelo.getPolicia().ingresarAutoSospechoso("limusina");break;
		}
	}
	
	public boolean escucharDeseaSalir(int opc) throws Exception{
		switch (opc){
		case 0:
			return false;
		case 1:
			return true;
		default:
			try{
				modelo.guardarPartida();
				vista.mensajeGuardarExito();
				return true;
			}
			catch (Exception e){
				vista.mensajeGuardarError();
				return true;
			}
		}
	}
	
	public boolean escucharMenuSeguirJugando(int opc) throws Exception{
		if (opc == 1){
			modelo.generarCaso();
			this.ladronAtrapado = false;
			this.ladronEscapo = false;
			this.edificiosSiendoVisitados = null;
			vista.pistaSexoLadron();
			vista.estadoDelJuego();
			return false;
		}
		else{
			int opcion_salir = vista.menuDeseaSalir();
			return this.escucharDeseaSalir(opcion_salir);
		}
	}
		
}
